#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include "nm.h"

using namespace std;

class Interface
{
    public:
    int interfaceEval(char* interface);
    int interfaceStatus(char* interface);
};

int Interface::interfaceEval(char*interface)
{
    char* inter=new char[7];
    int j=0;
    for(int i=0;i<=strlen(interface);i++)
    {
        if(interface[i]!=' ' && interface[i]!='\0')
        {
            inter[j]=interface[i];
            j++;
        }
        else
        {
            j++;
            inter[j]='\0';
            int ret=interfaceStatus(inter);
            if(!ret)
                return 0;       // make it zero
            if(!strcmp(inter,"wlan0"))
		if(!sine_shibboleth(inter))
			return 0;	
	    memset(inter,0,7);
            j=0;
        }
    }
    delete inter;
    return 1;
}

int Interface::interfaceStatus(char* interface)
{
    char* buffer=new char[10];
	memset (buffer,0,0);
	sine_getIfStatus(interface, buffer);
	if(!strcmp(buffer, "up"))
		return 1;
    	else
    	return 0;
   /* 
        //cout<<"Comparing - "<<interface<<endl;
    	if(!strcmp(interface,"wlan0"))
		return 1;
		else
		return 0;
*/}

class Location
{
    public:
    int resolveLocation(char* loc);
    int locationStatus(char* loc);
};

int Location::resolveLocation(char* location)
{
    char* loc=new char[15];
    int j=0;
    //cout<<"Processing - "<<location<<endl;
    for(int i=0;i<=strlen(location);i++)
    {
        if(location[i]!=' ' && location[i]!='\0')
        {
            loc[j]=location[i];
            j++;
        }
        else
        {
            j++;
            loc[j]='\0';
            int ret=locationStatus(loc);
            if(ret)
                return 1;       // make it zero
            memset(loc,0,15);
            j=0;
        }
    }
    delete loc;
    //cout<<"Should reach here\m";
    return 0;
}

int Location::locationStatus(char* location)
{
    /*char* buffer=new char[10];
	memset (buffer,0,0);
	sine_getIfStatus(buffer);
	if(!strcmp(buffer, location))
		return 1;
    	else
    	return 0;
    */
        //cout<<"Comparing - "<<location<<endl;
    	if(!strcmp(location,"columbia"))
		return 1;
		else
		return 0;
}



class Bandwidth
{
    public:
    int resolveBandwidth(int band);
};

int Bandwidth::resolveBandwidth(int band)
{
    int obtBand=510;
    //obtBand = sine_getBandwidth(interfaces[interfaceIndex]);
    //obtBand=atoi(strBand);
    if(band<=obtBand)
        return 1;
    else
        return 0;
}

class Cost
{
    public:
    int resolveCost(int cost);
};

int Cost::resolveCost(int cost)
{
    int obtCost=10;
    //obtCost = sine_getCost(interfaces[interfaceIndex]);
    //obtCost=atoi(strCost);
    if(cost>=obtCost)
        return 1;
    else
        return 0;
}

class DownloadLimit
{
    int resolvedwnLimit(int dwnlimit);
};

class ConditionList
{
    public:
    Location* location;
    Bandwidth* bandwidth;
    Cost* cost;
    DownloadLimit* dwnLimit;
};

class Action
{
    public:
    char* interface;
};

class Rules     // Similar to Conditions
{
    public:
    ConditionList* condList;
    Action* action;
};

class Policy
{
    public:
    int policyID;
    int appID;
    Rules* rule;
};

char* policyModel(int, int);
int evaluate (Action*, ConditionList*, char*, char*);
void parseCondition(char* tempStore,char* metadata,char* data, char* str,int condOffest,int init2,int dataIndex, int j);
/*
int main()
{
    char* interfaces=policyModel(77,1000);
    if(interfaces==NULL)
        cout<<"No available interfaces";
    else
        cout<<interfaces;
    return 0;
}*/

char* policyModel(int appID, int sockfd)
{
    //cout<<"trying to open file";
    ifstream in("configPolicy.txt"); // input
    if(!in) {
        cout << "Cannot open input file.\n";
        return NULL;
    }

    char* strAppID=new char[10];
    char str[150];
    char* metadata = new char[20];

    while(in)
    {
        //cout<<"Very first\n";
        in.getline(str, 150);
        //cout<<"Call reaches here\n";
        int dataIndex=0;
        unsigned int i=0;
       	for(i=0;i<strlen(str);i++)
   		{
            if(str[i]!=','){
           		strAppID[dataIndex]=str[i];
       			dataIndex++;
            }
	        else{
	             strAppID[dataIndex]='\0';
	             break;
	        }
    	}
    	int appIDSearch=atoi(strAppID);
    	if(appIDSearch!=appID)
    	{
    	    //delete str;
    	    //delete strAppID;
            //free(str);
            //cout<<"no - "<<appIDSearch<<endl;
    	    continue;
    	}

        else
        {
            //delete strAppID;
            cout<<"Working for appID "<<appIDSearch<<endl;
            Policy* policy=new Policy;
            policy->appID=appIDSearch;
            char* rCount=new char[1];
            rCount[0]=str[i+1];
            int ruleCount=atoi(rCount);
            delete rCount;
            //cout<<"1...\n";
            Rules* rules=new Rules[ruleCount];      // Set the # of rules.
            policy->rule=rules;

            for(int j=0;j<ruleCount;j++)        // looping for each condition
            {
                dataIndex=0;
                in.getline(str, 255);
                char*strCondCount = new char[5];
                for(i=0;i<strlen(str);i++)
                {
                    if(str[i]!=','){
                        strCondCount[dataIndex]=str[i];
                        dataIndex++;
                    }
                    else{
                        strCondCount[dataIndex]='\0';
                        break;
                    }
                }
                //cout<<"2....\n";
                int condCount = atoi(strCondCount);
                delete strCondCount;
                char* tempStore = new char[20];
                char* data1 = new char[10];      // Do not delete this pointer
                int interIndex=0;
                i++;

                ///////////////////

                while(i<strlen(str))
                {
                    tempStore[interIndex]=str[i];
                    i++;
                    interIndex++;
                }
                tempStore[interIndex]='\0';
                int init1=0;
                int j=0;
                    for(;init1<=strlen(tempStore);init1++)
                    {
                        if(tempStore[init1]!=' ' && tempStore[init1]!='\0')
                        {
                            metadata[j]=tempStore[init1];
                            j++;
                        }
                        else
                        {
                            j++;
                            metadata[j]='\0';
                            break;
                        }
                    }
                    init1=init1+1;
                    j=0;
                    for(;init1<=strlen(tempStore);init1++)
                    {
                        if(tempStore[init1]!=' ' && tempStore[init1]!='\0')
                        {
                            data1[j]=tempStore[init1];
                            j++;
                        }
                        else
                        {
                            j++;
                            data1[j]='\0';
                            break;
                        }
                    }
                    //cout<<"Got - "<<data1<<endl;


                Action* act=new Action; // Assigning actions to rules and itnerfaces to actions.
                ConditionList* cl=new ConditionList[condCount];
                rules[j].action=act;
                //cout<<"Got 1.1- "<<data1<<endl;

                rules[j].condList=cl;

                //cout<<"Got 2 - "<<data1<<endl;
                //cout<<"Got 2 - "<<metadata<<endl;

                if(!strcmp(metadata,"inter"))
                {
                    //cout<<"In the interface\n";
                    Interface* obj = new Interface;
                    act->interface=data1;
                    if(!(obj->interfaceEval(data1)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }
                    delete obj;
                }

                else if(!strcmp(metadata,"loc"))
                {
                    //cout<<"In the location\n";
                    Location* obj = new Location;
                    if(!(obj->resolveLocation(data1)))
                    {
                        //cout<<"Loc does not match "<<data1<<endl;
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;

                    }
                    delete obj;
                }

                else if(!strcmp(metadata,"band"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    Bandwidth* obj = new Bandwidth;
                    int band = atoi(data1);
                    /*if(!(obj->resolveBandwidth(band)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                else if(!strcmp(metadata,"cost"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    Cost* obj = new Cost;
                    int cost = atoi(data1);
                    /*if(!(obj->resolveCost(cost)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                else if(!strcmp(metadata,"limit"))
                {
                    //act->interface=interfaces;    // we assign the act->interface later on.
                    DownloadLimit* obj = new DownloadLimit;
                    int limit = atoi(data1);
                    /*if(!(obj->resolvedwnLimit(limit)))
                    {
                        for(int i=0;i<condCount;i++)
                            in.getline(str, 255);
                        continue;
                    }*/
                    delete obj;
                }

                cout<<"Trying to check a condition\n";
                // Now loop for condCount
                for(int i=0;i<condCount;i++)
                {
                     in.getline(str, 255);
                    // cout<<"Here..... 2\n";

                     // Working on the first part
                     dataIndex=0;
                     int condOffest=0;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char* data2 = new char[20];
                     int init2=0;
                     j=0;
                     parseCondition(tempStore,metadata,data2,str,condOffest,init2, dataIndex, j);

                     int status = evaluate(act, cl, metadata, data2);

                    if(!status)
                        continue;


                    // Work on the second part
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     init2=0;
                     j=0;
                     char* data3 = new char[20];
                     parseCondition(tempStore,metadata,data3,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data3);
                     if(!status)
                        continue;


                    // Work on the third part
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char* data4 = new char[20];
                     init2=0;
                     j=0;
                     parseCondition(tempStore,metadata,data4,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data4);
                     if(!status)
                        continue;


                    // Work on the part4
                     dataIndex=0;
                     condOffest++;
                     memset(tempStore,0,20);
                     memset(metadata,0,10);
                     char* data5 = new char[20];
                     init2=0;
                     j=0;
                     parseCondition(tempStore,metadata,data4,str,condOffest,init2, dataIndex, j);
                     status = evaluate(act, cl, metadata, data5);
                     if(!status)
                        continue;
                     //cout<<"???? \n";
                     delete[] metadata;
                     delete[] tempStore;
                     sine_setHipIf(sockfd, act->interface);
                 //cout<<"!!!!!\n";
                     return act->interface;

                }   // Condition loop ends
            }
            return NULL;
        }   // else ends (I am checking the right policy)
    }   // while ends
}   // function returns


void parseCondition(char* tempStore,char* metadata,char* data2, char* str,int condOffest,int init2,int dataIndex, int j)
{
                     for(;condOffest<strlen(str);condOffest++)
                     {
                        if(str[condOffest]!=','){
                            tempStore[dataIndex]=str[condOffest];
                            dataIndex++;
                        }
                        else{
                            tempStore[dataIndex]='\0';
                            break;
                        }
                     }


                    for(;init2<=strlen(tempStore);init2++)
                    {
                        if(tempStore[init2]!=' ' && tempStore[init2]!='\0')
                        {
                            metadata[j]=tempStore[init2];
                            j++;
                        }
                        else
                        {
                            j++;
                            metadata[j]='\0';
                            break;
                        }
                    }
                    init2=init2+1;
                    j=0;
                    for(;init2<=strlen(tempStore);init2++)
                    {
                        if(tempStore[init2]!=' ' && tempStore[init2]!='\0')
                        {
                            data2[j]=tempStore[init2];
                            j++;
                        }
                        else
                        {
                            j++;
                            data2[j]='\0';
                            break;
                        }
                    }
}



int evaluate (Action* act, ConditionList* cl, char* metadata, char* data2)
{
                if(!strcmp(metadata,"inter"))
                {
                    act->interface=data2;
                    //cout<<"intermediate - "<<act->interface;

                    Interface* obj = new Interface;
                    if(!(obj->interfaceEval(data2)))
                        return 0;

                }

                else if(!strcmp(metadata,"loc"))
                {
                       cl->location=new Location;                   // Do not delete strLocation -> memory leak.
                      if(!((cl->location)->resolveLocation(data2)))
                        return 0;

                        delete cl->location;
                }

                else if(!strcmp(metadata,"band"))
                {
                     int bandwidth = atoi(data2);
                     cl->bandwidth=new Bandwidth;
                /*     if(!((cl->bandwidth)->resolveBandwidth(data2)))
                        return 0;
                 */
                     delete cl->bandwidth;
                }

                else if(!strcmp(metadata,"cost"))
                {
                     int cost = atoi(data2);
                     cl->cost=new Cost;
                /*     if(!((cl->cost)->resolveCost(cost)))
                        return 0;
                 */
                     delete cl->cost;
                }

                else if(!strcmp(metadata,"limit"))
                {
                    int download = atoi(data2);
                    cl->dwnLimit=new DownloadLimit;
           /*          if(!((cl->dwnLimit)->resolvedwnLimit(download)))
                        return 0;
            */
                    delete cl->dwnLimit;
                }
                //cout<<"Should get - "<<data2<<endl;
                return 1;
}
